
/**
\file Specialisation of nmn::math::vector for booleans.
\author Sean Tromans
*/

#include <needs_more_ninja/preprocessor/assert/assert.hpp>

#define NMN_MATH_VECTOR_SET_ARRAY( z, n, _ )	m_bitset[n] = BOOST_PP_CAT( p, n );

#define NMN_MATH_VECTOR_CONSTRUCTOR( z, n, _ )	\
	template< size_t Size >	\
	inline vector< bool, Size >::vector( BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(n), bool p) )	\
	{	\
		static_assert( static_size == BOOST_PP_INC(n), "Invalid number of parameters." );	\
		BOOST_PP_CAT( BOOST_PP_REPEAT_, z )( BOOST_PP_INC(n), NMN_MATH_VECTOR_SET_ARRAY, _ );	\
	}

namespace nmn
{

	namespace math
	{

		/**
		Default Constructor. Does nothing.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline vector< bool, Size >::vector( )
		{
		}

		/**
		Copy construct from another vector of the same size, but potentially a different type.
		@param rhs The vector to copy.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline vector< bool, Size >::vector( typename vector< bool, Size >::my_type const & rhs )
			:	m_bitset( rhs.m_bitset )
		{
		}

		/**
		Set all components of the vector to the same inital value.
		@param rhs The value to initialise with.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline vector< bool, Size >::vector( typename vector< bool, Size >::value_type const & rhs )
		{
			m_bitset.set( );
			if ( !rhs )
			{
				m_bitset = ~m_bitset;
			}
		}

		BOOST_PP_REPEAT_FROM_TO( 1, NMN_MATH_VECTOR_MAX_ARITY, NMN_MATH_VECTOR_CONSTRUCTOR, 0 );

		/**
		Assign this vector to be equal to another.
		@param rhs The vector to copy.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline typename vector< bool, Size >::my_type & vector< bool, Size >::operator = ( typename vector< bool, Size >::my_type const & rhs )
		{
			m_bitset = rhs.m_bitset;
			return *this;
		}

		/**
		The size of the vector.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline typename vector< bool, Size >::size_type vector< bool, Size >::size( ) const
		{
			return m_bitset.size( );
		}

		/**
		Test if all components of this vector are true.
		@return True if each component is true.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline bool vector< bool, Size >::all( ) const
		{
			return m_bitset.count( ) == size( );
		}

		/**
		Test if all components of this vector equal another.
		@param rhs The vector to compare against.
		@return True if each corresponding component in the two vectors are exactly equal.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline bool vector< bool, Size >::all( typename vector< bool, Size >::my_type const & rhs ) const
		{
			for ( size_t i = 0; i < size( ); ++i )
			{
				if ( at( i ) != rhs.at( i ) )
				{
					return false;
				}
			}

			return true;
		}

		/**
		Test if any of the components of this vector are true.
		@return True if any component is true.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline bool vector< bool, Size >::any( ) const
		{
			return m_bitset.any( );
		}

		/**
		Test if any of the components of this vector equal another.
		@param rhs The vector to compare against.
		@return True if each corresponding component in the two vectors are exactly equal.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline bool vector< bool, Size >::any( my_type const & rhs ) const
		{
			for ( size_t i = 0; i < size( ); ++i )
			{
				if ( at( i ) == rhs.at( i ) )
				{
					return true;
				}
			}

			return false;
		}

		/**
		Gets a component from inside the vector.
		@param index The index of the component to return.
		@return a reference to the component at \c index.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline typename vector< bool, Size >::reference_type vector< bool, Size >::operator[] ( typename vector< bool, Size >::size_type index )
		{
			return at( index );
		}

		/**
		Gets a component from inside the vector.
		@param index The index of the component to return.
		@return a constant reference to the component at \c index.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline typename vector< bool, Size >::const_reference_type vector< bool, Size >::operator[] ( typename vector< bool, Size >::size_type index ) const
		{
			return at( index );
		}

		/**
		Gets a component from inside the vector.
		@param index The index of the component to return.
		@return a reference to the component at \c index.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline typename vector< bool, Size >::reference_type vector< bool, Size >::at( typename vector< bool, Size >::size_type index )
		{
			NMN_ASSERT( index < Size );
			return m_bitset[index];
		}

		/**
		Gets a component from inside the vector.
		@param index The index of the component to return.
		@return a constant reference to the component at \c index.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline typename vector< bool, Size >::const_reference_type vector< bool, Size >::at( typename vector< bool, Size >::size_type index ) const
		{
			NMN_ASSERT( index < Size );
			return m_bitset[index];
		}

		/**
		Swaps this vector with another.
		@param rhs The vector to swap with.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline void vector< bool, Size >::swap(  typename vector< bool, Size >::my_type & rhs )
		{
			std::swap( m_bitset, rhs.m_bitset );
		}

		/**
		Converts the vector to a string.
		\author Sean Tromans
		*/
		template< size_t Size >
		inline std::string vector< bool, Size >::to_string( ) const
		{
			return m_bitset.to_string( );
		}

		/**
		\relates nmn::math::vector
		Outputs a vector to an output stream.
		@param os The output ostream.
		@param vec The vector to output.
		@return A reference to the output stream.
		\author Sean Tromans
		*/
		template < typename Elem, typename Traits, size_t Size >
		inline std::basic_ostream< Elem, Traits > & operator << ( std::basic_ostream< Elem, Traits > & os, vector< bool, Size > const & vec )
		{
			return os << "{ " << vec.to_string( ) << " }";
		}

		/**
		Component wise absolute equality check.
		@param lhs The first vector to compare.
		@param rhs The second vector to compare.
		@return true if the two vectors are exactly equal.
		\author Sean Tromans
		*/
		template < size_t Size >
		inline bool operator == ( vector< bool, Size > const & lhs, vector< bool, Size > const & rhs )
		{
			return lhs.all( rhs );
		}

	};

};

#undef	NMN_MATH_VECTOR_CONSTRUCTOR
#undef	NMN_MATH_VECTOR_SET_ARRAY
